// ****************************************************************************
//	Copyright (c) 2011 Daniel Watman
//	http://www.keycommander.net/
// ****************************************************************************
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//	
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//	
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ****************************************************************************
//	File: btn_test.c
//	Purpose: test of LCD switch SA6432 - cycle backlight colours and display test image
//	Author:	Daniel Watman
//	Created: 2011.02.24
//	Updated: 2011.02.24
//	Version: 1.0
//	Target:	Atmel AVR ATMEGA88
//	Compiler: AVR-GCC
// ****************************************************************************
//	Changes:
//		1.0	* Initial version
// ****************************************************************************
//	To do:
//		* Nothing, basic test works
// ****************************************************************************
//	Comments:
//		* This is just a quick test
// ****************************************************************************
//	Timer usage:
//		Timer2	general timing
//		
//	Pin usage:
//		PORTD:
//			6	SPI data
//			7	SPI clock
//		
//	Interrupts:
//		OUTPUT_COMPARE2A	1ms tick

#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>

#define UPDATE_DELAY 1000 //1sec at 8Mhz

typedef unsigned char  u08;
typedef unsigned int  u16;

volatile u16 nextupdate=0, time_ms=0;	//use for general timing
volatile u08 flg = 0;		//general purpose flags

u08 img[256] = {	// test image
	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x12, 	// col 0, 1
	0xFF, 0xFF, 0xFF, 0xF3, 0x00, 0x00, 0x00, 0x22, 	// col 2, 3
	0xFF, 0xFF, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x22, 	// col 4, 5
	0xFF, 0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x40, 0x00, 	// col 6, 7
	0x80, 0xFF, 0x7F, 0x00, 0x80, 0x00, 0x40, 0x00, 	// col 8, 9
	0xFF, 0xFF, 0xFF, 0xE3, 0x00, 0x00, 0x00, 0x42, 	// col 10, 11
	0xFF, 0xFF, 0xFF, 0xC7, 0x00, 0x00, 0x00, 0x44, 	// col 12, 13
	0xFF, 0xFF, 0xFF, 0xCF, 0x09, 0x00, 0x00, 0x48, 	// col 14, 15
	0xF0, 0xFF, 0xFF, 0xFF, 0x20, 0x00, 0x00, 0xE8, 	// col 16, 17
	0xE0, 0xFF, 0xFF, 0x67, 0x40, 0x00, 0x00, 0x62, 	// col 18, 19
	0xC0, 0xFF, 0xFF, 0x63, 0x40, 0x00, 0x00, 0x62, 	// col 20, 21
	0xC4, 0xFF, 0xFF, 0x43, 0x86, 0x00, 0x00, 0x02, 	// col 22, 23
	0x86, 0xFF, 0xFF, 0x07, 0x86, 0x00, 0x00, 0x04, 	// col 24, 25
	0x8E, 0xFF, 0xFF, 0x07, 0x89, 0x00, 0x00, 0x08, 	// col 26, 27
	0xCF, 0xFF, 0xFF, 0xFF, 0x28, 0x00, 0x00, 0x00, 	// col 28, 29
	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 	// col 30, 31
	0xFF, 0xFF, 0xFF, 0xFF, 0x44, 0x00, 0x00, 0x00, 	// col 32, 33
	0x87, 0xFF, 0xFF, 0xFF, 0x85, 0x00, 0x00, 0x08, 	// col 34, 35
	0x0E, 0xFF, 0xFF, 0x07, 0x0C, 0x01, 0x00, 0x04, 	// col 36, 37
	0x1C, 0xFF, 0xFF, 0x07, 0x18, 0x01, 0x00, 0x04, 	// col 38, 39
	0x18, 0xFF, 0xFF, 0xC7, 0x18, 0x01, 0x00, 0xC4, 	// col 40, 41
	0x18, 0xFF, 0xFF, 0xC7, 0x08, 0x01, 0x00, 0x04, 	// col 42, 43
	0x08, 0xFF, 0xFF, 0x0F, 0x00, 0x01, 0x00, 0x08, 	// col 44, 45
	0x00, 0xFF, 0xFF, 0x1F, 0x80, 0x00, 0x00, 0x10, 	// col 46, 47
	0xC0, 0xFF, 0xFF, 0x3F, 0x20, 0x00, 0x00, 0x48, 	// col 48, 49
	0xFF, 0xFF, 0xFF, 0xCF, 0x00, 0x00, 0x00, 0x88, 	// col 50, 51
	0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0x00, 0x00, 0x88, 	// col 52, 53
	0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0x01, 0x80, 0x00, 	// col 54, 55
	0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x80, 0x00, 	// col 56, 57
	0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0x00, 0x00, 0x88, 	// col 58, 59
	0xFF, 0xFF, 0xFF, 0x8F, 0x00, 0x00, 0x00, 0x88, 	// col 60, 61
	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00};	// col 62, 63

// send a bit-banged SPI byte to LCD button (SPI mode 1,1 MSB first)
void btn_send(u08 type, u08 data) {
	u08 i;

	data <<= 2;	// get rid of unused high bits (can't use this for 0x42 set RGB colour)

// start bit (7)
	PORTD |= 0x80;	// clk high
	PORTD &= ~0x40;	// data low
	__builtin_avr_delay_cycles(5);
	PORTD &= ~0x80;	// clk low
	__builtin_avr_delay_cycles(5);
	PORTD |= 0x80;	// clk high

// command/data bit (6)
	if (type == 0)	PORTD &= ~0x40;	// data low
	else 			PORTD |= 0x40;	// data high
	__builtin_avr_delay_cycles(5);
	PORTD &= ~0x80;	// clk low
	__builtin_avr_delay_cycles(5);
	PORTD |= 0x80;	// clk high

// data (5-0)
	for (i=0;i<6;i++) { // loop through data
		if ((data&0x80) == 0)	PORTD &= ~0x40;	// data low
		else 			PORTD |= 0x40;	// data high
		data <<=1;	// shift left, next bit
	__builtin_avr_delay_cycles(5);
	PORTD &= ~0x80;	// clk low
	__builtin_avr_delay_cycles(5);
	PORTD |= 0x80;	// clk high
	}

// end
	PORTD |= 0x80;	// clk and data high (idle)
}

int main (void) {
	u16 i;
	u08 col;
	cli();	// disable interrupts for initialisation

//PIN SETUP
	DDRD |= 0xC0;	// set pins as outputs
	PORTD |= 0x80;	// clk and data high (idle)

//INTERRUPTS AND TIMER SETUP

	//initialise timer2 for interrupt on overflow
	TCCR2B = 0x03;	//set prescaler (1 8 32 64 128 256 1024)
	OCR2A = 249;	// set TOP value of counter to set 1kHz rate
	TCCR2A = 0x02;	// set CTC mode
	TIMSK2 |= 0x02;	//enable timer2 compareA interrupt

	sei();	//enable interrupts

	time_ms = 0;		

	nextupdate = 1000;	// wait 1 sec before starting

	while (flg == 0);	// wait 1 sec before starting
	
	btn_send(1, 0x00);	// command, set address
	btn_send(0, 0x00);	// data, A8
	btn_send(0, 0x00);	// data, A7-4
	btn_send(0, 0x00);	// data, A3-0

	for (i=0;i<256;i++) {	// image data
		btn_send(0, (img[i]&0xFF));		// data, D3-D0
		btn_send(0, ((img[i]>>4)&0xFF));// data, D3-D0
	}
	btn_send(1, 0x03);	// command, end transmission

	col = 0x00;	// start with backlight off
	while (1) {
		if (flg & 0x01) {	//1 second
			col++;	// cycle through colours
			
			btn_send(1, 0x01);			// command, set colour
			btn_send(0, (col&0x3F));	// data, colour
			btn_send(1, 0x03);			// command, end transmission
			
			flg &= ~0x01;	//clear flag
		}
	}


}

//INTERRUPT SERVICE ROUTINES
ISR(SIG_OUTPUT_COMPARE2A) {	//1 ms "tick". Runs each time timer2 overflows.
	time_ms++;	//increment the time

	if (time_ms == nextupdate) {	//if it is time to do something
		nextupdate += UPDATE_DELAY;	//set when it will be time to do it again

		flg |= 0x01;	//set the flag so it will be done in the main program
	}
}

